//!
//! # Update object
//!
//!

use std::fmt::Debug;

use anyhow::Result;

use fluvio_protocol::{Encoder, Decoder, Version};
use fluvio_protocol::api::Request;

use crate::{UpdatableAdminSpec, TryEncodableFrom};
use crate::Status;
use crate::AdminPublicApiKey;
use super::{COMMON_VERSION, TypeBuffer};

#[derive(Debug, Default, Encoder, Decoder)]
pub struct UpdateRequest<S: UpdatableAdminSpec> {
    key: S::UpdateKey,
    pub action: S::UpdateAction,
}

impl<S> UpdateRequest<S>
where
    S: UpdatableAdminSpec,
{
    pub fn new(key: S::UpdateKey, action: S::UpdateAction) -> Self {
        Self { key, action }
    }

    pub fn with(key: S::UpdateKey, action: S::UpdateAction) -> Self {
        Self { key, action }
    }

    pub fn key(self) -> S::UpdateKey {
        self.key
    }

    pub fn action(self) -> S::UpdateAction {
        self.action
    }
}

// This can be auto generated by enum derive later
#[derive(Debug, Default, Encoder, Decoder)]
pub struct ObjectApiUpdateRequest(TypeBuffer);

impl<S> TryEncodableFrom<UpdateRequest<S>> for ObjectApiUpdateRequest
where
    S: UpdatableAdminSpec,
{
    fn try_encode_from(input: UpdateRequest<S>, version: Version) -> Result<Self> {
        Ok(Self(TypeBuffer::encode::<S, _>(input, version)?))
    }

    fn downcast(&self) -> Result<Option<UpdateRequest<S>>> {
        self.0.downcast::<S, _>()
    }
}

impl Request for ObjectApiUpdateRequest {
    const API_KEY: u16 = AdminPublicApiKey::Update as u16;
    const MIN_API_VERSION: i16 = 1; // previous version
    const DEFAULT_API_VERSION: i16 = COMMON_VERSION;
    type Response = Status;
}
